package com.tsfyun.scm.declarechannel.config;

import cn.hutool.core.util.IdUtil;
import com.alibaba.fastjson.JSONObject;
import com.tsfyun.scm.declarechannel.entity.MqData;
import com.tsfyun.scm.declarechannel.service.IMqDataService;
import com.tsfyun.scm.declarechannel.support.dingding.DingTalkNoticeUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageBuilder;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import javax.annotation.PostConstruct;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;

@Slf4j
@Component
public class DeclareNoticeSender implements RabbitTemplate.ConfirmCallback, RabbitTemplate.ReturnCallback {

    @Autowired
    private RabbitTemplate declareRabbitTemplate;

    @Autowired
    private NoticeProperties noticeProperties;

    @Autowired
    private IMqDataService mqDataService;

    @PostConstruct
    public void init() {
        declareRabbitTemplate.setConfirmCallback(this);
        declareRabbitTemplate.setReturnCallback(this);
    }

    /**
     * 发送消息
     * @param exchange 交换机
     * @param routingKey 路由键
     * @param messageStr 消息体
     */
    public void send(String exchange,String routingKey,String tenant,String messageStr) {
        try{
            String msgId = UUID.randomUUID().toString();
            CorrelationData correlationData = new CorrelationData(msgId);
            Message message = MessageBuilder.withBody(messageStr.getBytes("UTF-8")).setCorrelationId(msgId)
                    .setHeader("scm-tenant",tenant).build();

            //记录发送消息至数据库中
            MqData mqData = new MqData();
            mqData.setId(IdUtil.simpleUUID());
            mqData.setExchange(exchange);
            mqData.setRoutingKey(routingKey);
            mqData.setDateCreated(LocalDateTime.now());
            mqData.setMsgId(msgId);
            mqData.setContent(messageStr);
            Map<String, Object> msgHeaders = message.getMessageProperties().getHeaders();
            mqData.setHeaders(JSONObject.toJSONString(msgHeaders));
            mqDataService.save(mqData);

            //发送消息至MQ队列
            declareRabbitTemplate.send(exchange,routingKey,message,correlationData);
        }catch (UnsupportedEncodingException e){
            log.error("编码错误：",e);
        }
    }

    /*
     * 消息从交换机成功到达队列，则returnedMessage方法不会执行
     * 消息从交换机未能成功到达队列，则returnedMessage方法会执行
     */
    @Override
    public void returnedMessage(Message message, int replyCode, String replyText, String exchange, String routingKey) {
        log.info("消息无法被路由，被服务器退回>>>" + new String(message.getBody(), StandardCharsets.UTF_8) + ",应答码:" + replyCode
                + ",应答文本:" + replyText + ",交换机:" + exchange + ",路由键:" + routingKey);
    }

    /**
     * 发送确认
     * @param correlationData
     * @param ack
     * @param cause
     */
    @Override
    public void confirm(CorrelationData correlationData, boolean ack, String cause) {
        String msgId = correlationData.getId();
        String reason = "";
        if (!ack) {
            log.error("消息发送失败，【{}】，异常内容：【{}】",correlationData.toString(),cause);
            DingTalkNoticeUtil.send2DingDingOtherException("","本地报关服务","MQ消息发送失败",cause,null,noticeProperties.getDingdingUrl());
            reason = StringUtils.isEmpty(cause) ? "发送失败" : cause;
        } else {
            log.info("消息发送成功，【{}】】",correlationData.toString());
            reason = "发送成功";
        }
        MqData mqData = mqDataService.findByMsgId(msgId);
        if(Objects.nonNull(mqData)) {
            mqDataService.updateMsg(msgId,reason);
        }
    }
}